import './render'; // 初始化Canvas
import Enemy from './npc/enemy'; // 导入敌机类
import BackGround from './runtime/background'; // 导入背景类
import GameInfo from './runtime/gameinfo'; // 导入游戏UI类
import Music from './runtime/music'; // 导入音乐类
import DataBus from './databus'; // 导入数据类，用于管理游戏状态和数据
import { PREPARATION_AREA_HEIGHT, CHESS_HEIGHT } from './render';

const ENEMY_GENERATE_INTERVAL = 30;
const ctx = canvas.getContext('2d'); // 获取canvas的2D绘图上下文;

GameGlobal.databus = new DataBus(); // 全局数据管理，用于管理游戏状态和数据
GameGlobal.musicManager = new Music(); // 全局音乐管理实例

/**
 * 游戏主函数
 */
export default class Main {
  aniId = 0; // 用于存储动画帧的ID
  bg = new BackGround(); // 创建背景
  gameInfo = new GameInfo(); // 创建游戏UI显示

  constructor() {
    // 当开始游戏被点击时，重新开始游戏
    this.gameInfo.on('restart', this.start.bind(this));

    // 开始游戏
    this.start();
  }

  /**
   * 开始或重启游戏
   */
  start() {
    GameGlobal.databus.reset(); // 重置数据
    cancelAnimationFrame(this.aniId); // 清除上一局的动画
    this.aniId = requestAnimationFrame(this.loop.bind(this)); // 开始新的动画循环
    GameGlobal.databus.turn.next(); // 进入下一回合
  }

  /**
   * 随着帧数变化的敌机生成逻辑
   * 帧数取模定义成生成的频率
   */
  enemyGenerate() {
    if (GameGlobal.databus.turn.preparing) return; // 准备阶段不生成
    if (GameGlobal.databus.turn.generatedEnemiesCount >= GameGlobal.databus.turn.totalEnemiesCount) return; // 生成的敌机数量达到上限
    // 每30帧生成一个敌机
    if (GameGlobal.databus.frame % ENEMY_GENERATE_INTERVAL === 0) {
      const enemy = GameGlobal.databus.pool.getItemByClass('enemy', Enemy); // 从对象池获取敌机实例
      enemy.init(); // 初始化敌机
      GameGlobal.databus.enemys.push(enemy); // 将敌机添加到敌机数组中
      ++GameGlobal.databus.turn.generatedEnemiesCount; // 生成的敌机数量加1
    }
  }

  /**
   * 全局碰撞检测
   */
  collisionDetection() {
    // 检测子弹与敌机的碰撞
    GameGlobal.databus.bullets.forEach((bullet) => {
      for (let i = 0, il = GameGlobal.databus.enemys.length; i < il; i++) {
        const enemy = GameGlobal.databus.enemys[i];

        // 如果敌机存活并且发生了发生碰撞
        if (enemy.isCollideWith(bullet)) {
          enemy.hurt(bullet); // 敌机掉血
          break; // 退出循环
        }
      }
    });

    // 如果y值最大的敌人超出屏幕高度 - 备战席高度 - 棋子高度
    var allEnemies = GameGlobal.databus.enemys.filter((e) => e.isActive);
    var maxEnemy = allEnemies.reduce((max, enemy) => enemy.y > max.y ? enemy : max, allEnemies[0]);
    if (maxEnemy && maxEnemy.y > canvas.height - PREPARATION_AREA_HEIGHT - CHESS_HEIGHT) {
      GameGlobal.databus.gameOver(); // 游戏结束
    }
  }

  /**
   * canvas重绘函数
   * 每一帧重新绘制所有的需要展示的元素
   */
  render() {
    ctx.clearRect(0, 0, canvas.width, canvas.height); // 清空画布

    this.bg.render(ctx); // 绘制背景

    GameGlobal.databus.fighters.forEach((item, index) => item.render(ctx, index)); // 绘制所有出战棋子
    // GameGlobal.databus.handCards.forEach((item, index) => item.render(ctx, index)); // 绘制所有手牌

    GameGlobal.databus.bullets.forEach((item) => item.render(ctx)); // 绘制所有子弹
    GameGlobal.databus.enemys.forEach((item) => item.render(ctx)); // 绘制所有敌机
    this.gameInfo.render(ctx); // 绘制游戏UI
    GameGlobal.databus.animations.forEach((ani) => {
      if (ani.isPlaying) {
        ani.aniRender(ctx); // 渲染动画
      }
    }); // 绘制所有动画
  }

  // 游戏逻辑更新主函数
  update() {
    GameGlobal.databus.frame++; // 增加帧数

    if (GameGlobal.databus.isGameOver) {
      return;
    }

    this.bg.update(); // 更新背景

    GameGlobal.databus.fighters.forEach((item, index) => item.update(index)); // 更新所有出战棋子
    // GameGlobal.databus.handCards.forEach((item, index) => item.update(index)); // 更新所有手牌
    // 更新所有子弹
    GameGlobal.databus.bullets.forEach((item) => item.update());
    // 更新所有敌机
    GameGlobal.databus.enemys.forEach((item) => item.update());

    this.enemyGenerate(); // 生成敌机
    this.collisionDetection(); // 检测碰撞

    let currentTurn = GameGlobal.databus.turn;
    if(!currentTurn.preparing && currentTurn.generatedEnemiesCount >= currentTurn.totalEnemiesCount && GameGlobal.databus.enemys.every((e) => !e.isActive)) {
      // 处理所有敌机被击毁的情况
      GameGlobal.databus.turn.next(); // 进入下一回合
    }
  }

  // 实现游戏帧循环
  loop() {
    this.update(); // 更新游戏逻辑
    this.render(); // 渲染游戏画面

    // 请求下一帧动画
    this.aniId = requestAnimationFrame(this.loop.bind(this));
  }
}
